package com.skyolder.milkbee.web.rest;

import java.net.URI;
import java.net.URISyntaxException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javax.inject.Inject;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.codahale.metrics.annotation.Timed;
import com.skyolder.milkbee.domain.Category;
import com.skyolder.milkbee.domain.Moderator;
import com.skyolder.milkbee.domain.User;
import com.skyolder.milkbee.dto.CategoryTreeItem;
import com.skyolder.milkbee.dto.SimpleResult;
import com.skyolder.milkbee.security.SecurityUtils;
import com.skyolder.milkbee.service.CategoryService;
import com.skyolder.milkbee.service.ModeratorService;
import com.skyolder.milkbee.service.UserService;
import com.skyolder.milkbee.tool.WalkTree;
import com.skyolder.milkbee.web.rest.util.HeaderUtil;
import com.skyolder.milkbee.web.rest.util.PaginationUtil;

import io.swagger.annotations.ApiParam;

/**
 * REST controller for managing Category.
 */
@RestController
@RequestMapping("/api")
public class CategoryResource {

	private final Logger log = LoggerFactory.getLogger(CategoryResource.class);

	@Inject
	private CategoryService categoryService;
	@Inject
	private UserService userService;
	@Inject
	private ModeratorService moderatorService;

	/**
	 * POST /categories : Create a new category.
	 *
	 * @param category
	 *            the category to create
	 * @return the ResponseEntity with status 201 (Created) and with body the
	 *         new category, or with status 400 (Bad Request) if the category
	 *         has already an ID
	 * @throws URISyntaxException
	 *             if the Location URI syntax is incorrect
	 */
	@PostMapping("/categories")
	@Timed
	public ResponseEntity<Category> createCategory(@Valid @RequestBody Category category) throws URISyntaxException {
		log.debug("REST request to save Category : {}", category);
		if (category.getId() != null) {
			return ResponseEntity.badRequest().headers(
					HeaderUtil.createFailureAlert("category", "idexists", "A new category cannot already have an ID"))
					.body(null);
		}
		category.setCreatedAt(ZonedDateTime.now());
		if(category.getParentId()==null||category.getParentId()==0L){
			category.setLevel(0L);
			category.setParentId(0L);
		}else{
			Category prtcategory=categoryService.findOne(category.getParentId());
			if(prtcategory==null){
				category.setLevel(0L);
				category.setParentId(0L);
			}else if(prtcategory.getLevel()!=0L){
				//only two level
				category.setLevel(0L);
				category.setParentId(0L);
			}else{
				category.setLevel(1L);
			}
		}
		category.setCreator(SecurityUtils.getCurrentUserLogin());
		Category result = categoryService.save(category);
		return ResponseEntity.created(new URI("/api/categories/" + result.getId()))
				.headers(HeaderUtil.createEntityCreationAlert("category", result.getId().toString())).body(result);
	}

	/**
	 * PUT /categories : Updates an existing category.
	 *
	 * @param category
	 *            the category to update
	 * @return the ResponseEntity with status 200 (OK) and with body the updated
	 *         category, or with status 400 (Bad Request) if the category is not
	 *         valid, or with status 500 (Internal Server Error) if the category
	 *         couldnt be updated
	 * @throws URISyntaxException
	 *             if the Location URI syntax is incorrect
	 */
	@PutMapping("/categories")
	@Timed
	public ResponseEntity<Category> updateCategory(@Valid @RequestBody Category category) throws URISyntaxException {
		log.debug("REST request to update Category : {}", category);
		if (category.getId() == null) {
			return createCategory(category);
		}
		Category result = categoryService.save(category);
		return ResponseEntity.ok().headers(HeaderUtil.createEntityUpdateAlert("category", category.getId().toString()))
				.body(result);
	}

	/**
	 * GET /categories : get all the categories.
	 *
	 * @param pageable
	 *            the pagination information
	 * @return the ResponseEntity with status 200 (OK) and the list of
	 *         categories in body
	 * @throws URISyntaxException
	 *             if there is an error to generate the pagination HTTP headers
	 */
	@GetMapping("/categories")
	@Timed
	public ResponseEntity<List<Category>> getAllCategories(@ApiParam Pageable pageable) throws URISyntaxException {
		log.debug("REST request to get a page of Categories");
		Page<Category> page = categoryService.findAll(pageable);
		HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/categories");
		return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
	}

	/**
	 * GET /categories/:id : get the "id" category.
	 *
	 * @param id
	 *            the id of the category to retrieve
	 * @return the ResponseEntity with status 200 (OK) and with body the
	 *         category, or with status 404 (Not Found)
	 */
	@GetMapping("/categories/{id}")
	@Timed
	public ResponseEntity<Category> getCategory(@PathVariable Long id) {
		log.debug("REST request to get Category : {}", id);
		Category category = categoryService.findOne(id);
		return Optional.ofNullable(category).map(result -> new ResponseEntity<>(result, HttpStatus.OK))
				.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
	}

	/**
	 * DELETE /categories/:id : delete the "id" category.
	 *
	 * @param id
	 *            the id of the category to delete
	 * @return the ResponseEntity with status 200 (OK)
	 */
	@DeleteMapping("/categories/{id}")
	@Timed
	public ResponseEntity<Void> deleteCategory(@PathVariable Long id) {
		log.debug("REST request to delete Category : {}", id);
		categoryService.delete(id);
		return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert("category", id.toString())).build();
	}

	@GetMapping("/subcategories/{parentId}")
	@Timed
	public ResponseEntity<List<Category>> getSubCategories(@PathVariable Long parentId) throws URISyntaxException {
		log.debug("REST request to delete Category : {}", parentId);
		List<Category> list = categoryService.findByParentId(parentId);
		return new ResponseEntity<>(list, HttpStatus.OK);
	}
	@GetMapping("/categoriesbylevel/{level}")
	@Timed
	public ResponseEntity<List<Category>> getCategoriesByLevel(@PathVariable Long level) throws URISyntaxException {
		List<Category> list = categoryService.findByLevel(level);
		return new ResponseEntity<>(list, HttpStatus.OK);
	}

	/**
	 * only two level
	 * 
	 * @return
	 * @throws URISyntaxException
	 */
	@GetMapping("/treecategories")
	@Timed
	public ResponseEntity<List<CategoryTreeItem>> getTreeCategories() throws URISyntaxException {
		List<Category> list0 = categoryService.findAll();
		List<CategoryTreeItem> list1 = new ArrayList<CategoryTreeItem>();
		for (Category c : list0) {
			if (c.getLevel() == 0) {
				CategoryTreeItem item = new CategoryTreeItem();
				item.setLeaf(true);
				item.setNode(c);
				list1.add(item);
			}
		}

		for (Category c : list0) {
			if (c.getLevel() == 1) {
				for (CategoryTreeItem titem : list1) {
					CategoryTreeItem parent = WalkTree.findParent(titem, c.getParentId());
					if (parent != null) {
						CategoryTreeItem child = new CategoryTreeItem();
						child.setNode(c);
						child.setLeaf(true);
						parent.addChild(child);
						parent.setLeaf(false);

					}
				}
			}
		}

		return new ResponseEntity<>(list1, HttpStatus.OK);
	}
	
	@GetMapping("/allcategories")
	@Timed
	public ResponseEntity<List<Category>> getAllCategories() throws URISyntaxException {
		List<Category> list = categoryService.findAll();
		return new ResponseEntity<>(list, HttpStatus.OK);
	}
	
	@GetMapping("/modcategories")
	@Timed
	public ResponseEntity<List<Category>> getAllModCategory(@ApiParam Pageable pageable) throws URISyntaxException {
		log.debug("REST request to get a page of Categories");
		Optional<User> ouser = userService.getUserWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin());
		User user = ouser.get();
		Long userId = user.getId();
		List<Moderator> moderators=moderatorService.findByUserId(userId);
		List<Long> categoryIds=new ArrayList<Long>();
		for(Moderator m:moderators){
			categoryIds.add(m.getCategoryId());
		}
		
		Page<Category> page = categoryService.doQueryByIds(categoryIds,pageable);
		HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/modcategories");
		return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
	}
	
	@PutMapping("/category/secede/{id}")
	@Timed
	public ResponseEntity<SimpleResult> applyEssence(@PathVariable Long id) throws URISyntaxException {
		SimpleResult sr = new SimpleResult();
		Optional<User> ouser = userService.getUserWithAuthoritiesByLogin(SecurityUtils.getCurrentUserLogin());
		User user = ouser.get();
		Long userId = user.getId();
		List<Moderator> moderators=moderatorService.findByUserId(userId);
		Long fid=null;
		for(Moderator m:moderators){
			if(m.getCategoryId()==id){
				fid=m.getId();
				break;
			}
		}
		if(fid==null){
			sr.setSuccess(false);
			return new ResponseEntity<>(sr, HttpStatus.NOT_FOUND);
		}
		moderatorService.delete(fid);
		sr.setSuccess(true);
		return new ResponseEntity<>(sr, HttpStatus.OK);
	}
}
